#include "heaptimer.h"

// 上浮操作，用于在堆中插入新节点或调整节点位置
void HeapTimer::siftup_(size_t i) {
    assert(i >= 0 && i < heap_.size());
    size_t j = (i - 1) / 2;     // 插入的父节点下标
    while(j >= 0)
    {
        if(heap_[j] < heap_[i]) {break;}
        SwapNode_(i, j);
        i = j;
        j = (i - 1) / 2;
    }
}

void HeapTimer::SwapNode_(size_t i, size_t j) {
    assert(i >= 0 && i < heap_.size());
    assert(j >= 0 && j < heap_.size());
    std::swap(heap_[i], heap_[j]);
    ref_[heap_[i].id] = i;      // 建立id对于index的映射
    ref_[heap_[j].id] = j;
    
}

// 下沉操作，用于将指定索引节点下沉至正确位置以维持堆属性
bool HeapTimer::siftdown_(size_t index, size_t n) {
    assert(index >= 0 && index < heap_.size());
    assert(n >= 0 && n <= heap_.size());

    size_t i = index;
    size_t j = i * 2 + 1;       // 左子节点
    while(j < n) {
        // 在左右子节点中找到较小的子节点
        if(j + 1 < n && heap_[j + 1] < heap_[j]) j++;
        if(heap_[i] < heap_[j])  break;

        SwapNode_(i, j);
        i = j;
        j = i * 2 + 1;
    }
    return i > index;

}

 // 向定时器添加一个新的定时任务
void HeapTimer::add(int id, int timeout, const TimeoutCallBack& cb) {
    assert(id >= 0);
    size_t i;
    if(ref_.count(id) == 0) {
        // 插入新节点
        i = heap_.size();
        ref_[id] = i;   // 建立id与index之间的映射
        heap_.push_back({id, Clock::now() + MS(timeout), cb});
        siftup_(i);     // 向上调整
    } else {
        // 该节点已经存在,覆盖信息
        i = ref_[id];
        heap_[i].expires = Clock::now() + MS(timeout);
        heap_[i].cb = cb;
        if(!siftdown_(i, heap_.size())) {
            siftup_(i);
        }
    }
}

// 执行指定ID的定时任务并从堆中移除
void HeapTimer::doWork(int id) {
    if(heap_.empty() || ref_.count(id) == 0) {
        return;
    }
    size_t i = ref_[id];    // 根据id查找对应的下标
    TimerNode node = heap_[i];
    node.cb();
    del_(i);
}

// 根据索引从堆中删除指定的时间任务节点
void HeapTimer::del_(size_t index) {
    assert(!heap_.empty() && index >= 0 && index < heap_.size());
    // 将删除节点调换到队尾
    size_t i = index;
    size_t n = heap_.size() - 1;
    assert(i <= n);
    if(i < n) {       // 不是队尾元素
        SwapNode_(i, n); // 与队尾元素交换
        if(!siftdown_(i, n)) {   // 向下调整
            siftup_(i);  // 否则向上调整
        }
    }

    ref_.erase(heap_.back().id);// 删除对应的id
    heap_.pop_back();           // 删除堆尾部元素
}

// 根据ID调整指定任务的新的超时时间
void HeapTimer::adjust(int id, int timeout) {
    assert(!heap_.empty() && ref_.count(id) > 0);           // 堆非空且id存在
    heap_[ref_[id]].expires = Clock::now() + MS(timeout);   // 重新调整时间
    siftdown_(ref_[id], heap_.size());
}

// 检查并执行所有到期的定时任务
void HeapTimer::tick() {
    if(heap_.empty()) {
        return;
    }
    while(!heap_.empty()) {
        TimerNode node = heap_.front();
        // 时间未到
        if(std::chrono::duration_cast<MS>(node.expires - Clock::now()).count() > 0) {
            break;
        }
        //时间到
        node.cb();
        pop();   // 删除堆头
    }
}

// 移除并处理堆顶（最早超时）的任务
void HeapTimer::pop() {
    assert(!heap_.empty());
    del_(0);
}

// 清除所有定时任务
void HeapTimer::clear() {
    ref_.clear();
    heap_.clear();
}

// 获取下一个定时任务的剩余时间（毫秒）
int HeapTimer::GetNextTick() {
    tick();
    size_t res = -1;    // 默认一直阻塞
    if(!heap_.empty()) {
        res = std::chrono::duration_cast<MS>(heap_.front().expires - Clock::now()).count();
        if(res < 0) {res = 0;}      // 表示立即触发
    }
    return res;
}